package com.xyht.sca_s.student_manage_system.modules.appDynamic.util;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ExceptionCast;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.appDynamic.entity.*;
import com.xyht.sca_s.student_manage_system.modules.appDynamic.entity.req.ApplicationDataReq;
import com.xyht.sca_s.student_manage_system.modules.appDynamic.entity.resp.ApplicationDataResp;
import com.xyht.sca_s.student_manage_system.modules.appDynamic.entity.resp.ControlInfoResp;
import com.xyht.sca_s.student_manage_system.modules.appDynamic.mapper.*;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.*;
import com.xyht.sca_s.student_manage_system.modules.newTips.util.NewTipsUtil;
import com.xyht.sca_s.student_manage_system.modules.org.entity.SmsOrgStructure;
import com.xyht.sca_s.student_manage_system.modules.org.mapper.SmsOrgStructureMapper;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.appDynamic.constant.ApproverTypeConstant.DYNAMIC_APP_ASSIGNER;
import static com.xyht.sca_s.student_manage_system.modules.appDynamic.constant.ApproverTypeConstant.DYNAMIC_APP_ROLE;
import static com.xyht.sca_s.student_manage_system.modules.appDynamic.constant.ConditionControlSubTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.appDynamic.constant.ControlTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.appDynamic.constant.NodeAllowTypeConstant.NODE_ALLOW_STATUS_PASS;
import static com.xyht.sca_s.student_manage_system.modules.appDynamic.constant.NodeTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.appDynamic.constant.NoticeTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.CopyTypeEnum.COPY_TYPE_ENUM_NONE;

@Component
public class AppDynamicUtil {
    @Resource
    private AppApplicationMapper appApplicationMapper;
    @Resource
    private AppBasicInfoMapper appBasicInfoMapper;
    @Resource
    private AppApplicationDataMapper appApplicationDataMapper;
    @Resource
    private AppControlOrderMapper appControlOrderMapper;
    @Resource
    private AppTextControlConfigMapper appTextControlConfigMapper;
    @Resource
    private AppTimeControlConfigMapper appTimeControlConfigMapper;
    @Resource
    private AppOptionControlConfigMapper appOptionControlConfigMapper;
    @Resource
    private AppStepperControlConfigMapper appStepperControlConfigMapper;
    @Resource
    private AppFileControlConfigMapper appFileControlConfigMapper;
    @Resource
    private AppProcessNodeConfigMapper appProcessNodeConfigMapper;
    @Resource
    private AppProcessNodeDetailMapper appProcessNodeDetailMapper;
    @Resource
    private SmsOrgStructureMapper smsOrgStructureMapper;
    @Resource
    private CacheUtil cacheUtil;
    @Resource
    private NewTipsUtil newTipsUtil;

    /**
     * 获取申请表数据
     *
     * @param applicationId 申请表id
     * @return 数据集合
     */
    public List<ApplicationDataResp> getDataRespList(String applicationId) {
        List<ApplicationDataResp> dataRespList = new ArrayList<>();
        List<AppApplicationData> dataList = appApplicationDataMapper.selectList(new LambdaQueryWrapper<AppApplicationData>()
                .eq(AppApplicationData::getApplicationId, applicationId));
        for (AppApplicationData appApplicationData : dataList) {
            AppControlOrder appControlOrder = appControlOrderMapper.selectControlOrder(appApplicationData.getControlOrderId());
            ApplicationDataResp dataResp = new ApplicationDataResp();
            dataResp.setIsShow(appControlOrder.getIsShow());
            dataResp.setSort(appControlOrder.getSort());
            dataResp.setId(appControlOrder.getId());
            String type = appControlOrder.getType();
            if (!isNullOrEmpty(appApplicationData.getData())) {
                if (type.equals(CONDITION_SUBTYPE_ORGANIZATION)) {
                    SmsOrgStructure smsOrgStructure = smsOrgStructureMapper.selectById(appApplicationData.getData());
                    if (!isNullOrEmpty(smsOrgStructure)) {
                        dataResp.setData(smsOrgStructure.getOrgName());
                    }
                } else {
                    dataResp.setData(appApplicationData.getData());
                }
            }
            if (Arrays.asList(TextControlType).contains(type)) {
                AppTextControlConfig textControlConfig = appTextControlConfigMapper.selectTextControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(textControlConfig.getName());
                dataResp.setType(textControlConfig.getSubType());
            } else if (Arrays.asList(TimeControlType).contains(type)) {
                AppTimeControlConfig timeControlConfig = appTimeControlConfigMapper.selectTimeControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(timeControlConfig.getName());
                dataResp.setType(timeControlConfig.getSubType());
            } else if (Arrays.asList(OptionControlType).contains(type)) {
                AppOptionControlConfig optionControlConfig = appOptionControlConfigMapper.selectOptionControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(optionControlConfig.getName());
                dataResp.setType(optionControlConfig.getSubType());
            } else if (Arrays.asList(StepperControlType).contains(type)) {
                AppStepperControlConfig stepperControlConfig = appStepperControlConfigMapper.selectStepperControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(stepperControlConfig.getName());
                dataResp.setType(stepperControlConfig.getSubType());
            } else if (Arrays.asList(FileControlType).contains(type)) {
                AppFileControlConfig fileControlConfig = appFileControlConfigMapper.selectFileControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(fileControlConfig.getName());
                dataResp.setType(fileControlConfig.getSubType());
            }
            dataRespList.add(dataResp);
        }
        return dataRespList;
    }

    /**
     * 获取申请表数据
     *
     * @param applicationId      申请表id
     * @param controlOrderIdList 控件id集合
     * @return 申请表数据集合
     */
    public List<ApplicationDataResp> getDataRespList(String applicationId, List<String> controlOrderIdList) {
        List<ApplicationDataResp> dataRespList = new ArrayList<>();
        List<AppApplicationData> dataList = appApplicationDataMapper.selectList(new LambdaQueryWrapper<AppApplicationData>()
                .eq(AppApplicationData::getApplicationId, applicationId));
        for (AppApplicationData appApplicationData : dataList) {
            AppControlOrder appControlOrder = appControlOrderMapper.selectControlOrder(appApplicationData.getControlOrderId());
            if (!controlOrderIdList.contains(appControlOrder.getId())) {
                continue;
            }
            ApplicationDataResp dataResp = new ApplicationDataResp();
            dataResp.setIsShow(appControlOrder.getIsShow());
            dataResp.setSort(appControlOrder.getSort());
            dataResp.setId(appControlOrder.getId());
            if (!isNullOrEmpty(appApplicationData.getData())) {
                dataResp.setData(appApplicationData.getData());
            }
            String type = appControlOrder.getType();
            if (Arrays.asList(TextControlType).contains(type)) {
                AppTextControlConfig textControlConfig = appTextControlConfigMapper.selectTextControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(textControlConfig.getName());
                dataResp.setType(textControlConfig.getSubType());
            } else if (Arrays.asList(TimeControlType).contains(type)) {
                AppTimeControlConfig timeControlConfig = appTimeControlConfigMapper.selectTimeControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(timeControlConfig.getName());
                dataResp.setType(timeControlConfig.getSubType());
            } else if (Arrays.asList(OptionControlType).contains(type)) {
                AppOptionControlConfig optionControlConfig = appOptionControlConfigMapper.selectOptionControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(optionControlConfig.getName());
                dataResp.setType(optionControlConfig.getSubType());
            } else if (Arrays.asList(StepperControlType).contains(type)) {
                AppStepperControlConfig stepperControlConfig = appStepperControlConfigMapper.selectStepperControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(stepperControlConfig.getName());
                dataResp.setType(stepperControlConfig.getSubType());
            } else if (Arrays.asList(FileControlType).contains(type)) {
                AppFileControlConfig fileControlConfig = appFileControlConfigMapper.selectFileControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(fileControlConfig.getName());
                dataResp.setType(fileControlConfig.getSubType());
            }
            dataRespList.add(dataResp);
        }
        return dataRespList;
    }

    /**
     * 获取申请表数据
     *
     * @param applicationId  申请表id
     * @param controlSortArr 控件顺序数组
     * @return 申请表数据集合
     */
    public List<ApplicationDataResp> getDataRespList(String applicationId, int[] controlSortArr) {
        List<ApplicationDataResp> dataRespList = new ArrayList<>();
        List<AppApplicationData> dataList = appApplicationDataMapper.selectList(new LambdaQueryWrapper<AppApplicationData>()
                .eq(AppApplicationData::getApplicationId, applicationId));
        for (AppApplicationData appApplicationData : dataList) {
            AppControlOrder appControlOrder = appControlOrderMapper.selectControlOrder(appApplicationData.getControlOrderId());
            if (!ArrayUtils.contains(controlSortArr, appControlOrder.getSort())) {
                continue;
            }
            ApplicationDataResp dataResp = new ApplicationDataResp();
            dataResp.setIsShow(appControlOrder.getIsShow());
            dataResp.setSort(appControlOrder.getSort());
            dataResp.setId(appControlOrder.getId());
            if (!isNullOrEmpty(appApplicationData.getData())) {
                dataResp.setData(appApplicationData.getData());
            }
            String type = appControlOrder.getType();
            if (Arrays.asList(TextControlType).contains(type)) {
                AppTextControlConfig textControlConfig = appTextControlConfigMapper.selectTextControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(textControlConfig.getName());
                dataResp.setType(textControlConfig.getSubType());
            } else if (Arrays.asList(TimeControlType).contains(type)) {
                AppTimeControlConfig timeControlConfig = appTimeControlConfigMapper.selectTimeControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(timeControlConfig.getName());
                dataResp.setType(timeControlConfig.getSubType());
            } else if (Arrays.asList(OptionControlType).contains(type)) {
                AppOptionControlConfig optionControlConfig = appOptionControlConfigMapper.selectOptionControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(optionControlConfig.getName());
                dataResp.setType(optionControlConfig.getSubType());
            } else if (Arrays.asList(StepperControlType).contains(type)) {
                AppStepperControlConfig stepperControlConfig = appStepperControlConfigMapper.selectStepperControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(stepperControlConfig.getName());
                dataResp.setType(stepperControlConfig.getSubType());
            } else if (Arrays.asList(FileControlType).contains(type)) {
                AppFileControlConfig fileControlConfig = appFileControlConfigMapper.selectFileControlConfig(appApplicationData.getControlOrderId());
                dataResp.setName(fileControlConfig.getName());
                dataResp.setType(fileControlConfig.getSubType());
            }
            dataRespList.add(dataResp);
        }
        dataRespList.sort(new Comparator<ApplicationDataResp>() {
            @Override
            public int compare(ApplicationDataResp o1, ApplicationDataResp o2) {
                return o1.getSort().compareTo(o2.getSort());
            }
        });
        return dataRespList;
    }

    /**
     * 获取某应用控件名集合
     *
     * @param appId    应用id
     * @param sortList 控件顺序集合,若查全部则传null
     * @return 控件名集合
     */
    public List<ControlInfoResp> getControlInfoList(String appId, List<Integer> sortList) {
        //构造查询条件
        LambdaQueryWrapper<AppControlOrder> queryWrapper = new LambdaQueryWrapper<AppControlOrder>()
                .eq(AppControlOrder::getAppId, appId)
                .orderByAsc(AppControlOrder::getSort);
        if (!isNullOrEmpty(sortList)) {
            queryWrapper.in(AppControlOrder::getSort, sortList);
        }
        //获取当前应用所有控件名
        List<AppControlOrder> controlOrderList = appControlOrderMapper.selectList(queryWrapper);
        List<ControlInfoResp> controlInfoRespList = new ArrayList<>();
        for (AppControlOrder controlOrder : controlOrderList) {
            ControlInfoResp controlInfoResp = new ControlInfoResp();
            controlInfoResp.setId(controlOrder.getId());
            controlInfoResp.setSort(controlOrder.getSort());
            String type = controlOrder.getType();
            if (Arrays.asList(TextControlType).contains(type)) {
                AppTextControlConfig textControlConfig = appTextControlConfigMapper.selectTextControlConfig(controlOrder.getId());
                controlInfoResp.setName(textControlConfig.getName());
                controlInfoResp.setType(textControlConfig.getSubType());
            } else if (Arrays.asList(TimeControlType).contains(type)) {
                AppTimeControlConfig timeControlConfig = appTimeControlConfigMapper.selectTimeControlConfig(controlOrder.getId());
                controlInfoResp.setName(timeControlConfig.getName());
                controlInfoResp.setType(timeControlConfig.getSubType());
            } else if (Arrays.asList(OptionControlType).contains(type)) {
                AppOptionControlConfig optionControlConfig = appOptionControlConfigMapper.selectOptionControlConfig(controlOrder.getId());
                controlInfoResp.setName(optionControlConfig.getName());
                controlInfoResp.setType(optionControlConfig.getSubType());
            } else if (Arrays.asList(StepperControlType).contains(type)) {
                AppStepperControlConfig stepperControlConfig = appStepperControlConfigMapper.selectStepperControlConfig(controlOrder.getId());
                controlInfoResp.setName(stepperControlConfig.getName());
                controlInfoResp.setType(stepperControlConfig.getSubType());
            } else if (Arrays.asList(FileControlType).contains(type)) {
                AppFileControlConfig fileControlConfig = appFileControlConfigMapper.selectFileControlConfig(controlOrder.getId());
                controlInfoResp.setName(fileControlConfig.getName());
                controlInfoResp.setType(fileControlConfig.getSubType());
            }
            controlInfoRespList.add(controlInfoResp);
        }
        return controlInfoRespList;
    }

    /**
     * 传入 控件id 返回 该控件是否必填
     *
     * @param controlOrderId 控件id
     * @return 是否必填
     */
    public Boolean getIsRequired(String controlOrderId) {
        AppControlOrder appControlOrder = appControlOrderMapper.selectControlOrder(controlOrderId);
        if (isNullOrEmpty(appControlOrder)) {
            return null;
        }
        String type = appControlOrder.getType();
        if (Arrays.asList(TextControlType).contains(type)) {
            AppTextControlConfig textControlConfig = appTextControlConfigMapper.selectTextControlConfig(controlOrderId);
            return textControlConfig.getRequired();
        } else if (Arrays.asList(TimeControlType).contains(type)) {
            AppTimeControlConfig timeControlConfig = appTimeControlConfigMapper.selectTimeControlConfig(controlOrderId);
            return timeControlConfig.getRequired();
        } else if (Arrays.asList(OptionControlType).contains(type)) {
            AppOptionControlConfig optionControlConfig = appOptionControlConfigMapper.selectOptionControlConfig(controlOrderId);
            return optionControlConfig.getRequired();
        } else if (Arrays.asList(StepperControlType).contains(type)) {
            AppStepperControlConfig stepperControlConfig = appStepperControlConfigMapper.selectStepperControlConfig(controlOrderId);
            return stepperControlConfig.getRequired();
        } else if (Arrays.asList(FileControlType).contains(type)) {
            AppFileControlConfig fileControlConfig = appFileControlConfigMapper.selectFileControlConfig(controlOrderId);
            return fileControlConfig.getRequired();
        }
        return null;
    }

    /**
     * 判断是否符合全部条件
     *
     * @param dataReqList   接收表单数据集合
     * @param conditionList 条件设置集合
     * @param userId        用户id
     * @return 是否符合全部条件
     */
    public boolean getIsReachedConditionList(List<ApplicationDataReq> dataReqList, List<AppCondition> conditionList, String userId) {
        List<AppCondition> collect = conditionList.stream().filter(condition -> {
            String conditionSubType = condition.getControlSubType();
            Integer conditionSort = condition.getSort();
            if (condition.getIsSubmitter() && conditionSubType.equals(CONDITION_SUBTYPE_SUBMITTER)) {//提交人
                List<String> roleList = cacheUtil.getRoleList(userId);
                switch (conditionSort) {
                    //属于
                    case 0:
                        return roleList.contains(condition.getData());
                    //不属于
                    case 1:
                        return !roleList.contains(condition.getData());
                    default:
                        return false;
                }
            } else if (!isNullOrEmpty(condition.getControlSubType())) {//其他条件
                //匹配到对应的数据
                String dataReq = dataReqList.stream().filter(data ->
                                data.getControlOrderId().equals(condition.getControlOrderId())).collect(Collectors.toList())
                        .get(0).getData();
                switch (conditionSubType) {
                    case CONDITION_SUBTYPE_RADIO://单选
                    case CONDITION_SUBTYPE_POPUP_RADIO://单选弹出
                    case CONDITION_SUBTYPE_ORGANIZATION://组织
                        switch (conditionSort) {
                            //等于
                            case 0:
                                return condition.getData().equals(dataReq);
                            //不等于
                            case 1:
                                return !condition.getData().equals(dataReq);
                            default:
                                return false;
                        }
                    case CONDITION_SUBTYPE_CHECKBOX://多选
                        List<String> radioReqList = JSON.parseArray(dataReq, String.class);
                        List<String> radioList = JSON.parseArray(condition.getData(), String.class);
                        switch (conditionSort) {
                            //完全匹配
                            case 0:
                                return new HashSet<>(radioReqList).containsAll(radioList);
                            //包含以下任意
                            case 1:
                                boolean flagA = false;
                                for (String radio : radioList) {
                                    if (radioReqList.contains(radio)) {
                                        flagA = true;
                                        break;
                                    }
                                }
                                return flagA;
                            //不包含
                            case 2:
                                boolean flagB = true;
                                for (String radio : radioList) {
                                    if (radioReqList.contains(radio)) {
                                        flagB = false;
                                        break;
                                    }
                                }
                                return flagB;
                            default:
                                return false;
                        }
                    case CONDITION_SUBTYPE_NUMBER://数字/金额
                    case CONDITION_SUBTYPE_STEPPER://步进器
                        //接收到的 数字/金额
                        double numberReq = Double.parseDouble(dataReq);
                        //条件设置的 数字/金额
                        double number = Double.parseDouble(condition.getData());
                        switch (conditionSort) {
                            //小于
                            case 0:
                                return Double.doubleToLongBits(numberReq) < Double.doubleToLongBits(number);
                            //小于等于
                            case 1:
                                return Double.doubleToLongBits(numberReq) <= Double.doubleToLongBits(number);
                            //等于
                            case 2:
                                return Double.doubleToLongBits(numberReq) == Double.doubleToLongBits(number);
                            //大于等于
                            case 3:
                                return Double.doubleToLongBits(numberReq) >= Double.doubleToLongBits(number);
                            //大于
                            case 4:
                                return Double.doubleToLongBits(numberReq) > Double.doubleToLongBits(number);
                            default:
                                return false;
                        }
                    case CONDITION_SUBTYPE_SINGLE://单个日期
                        //接收到的日期
                        Date dateReq = TimeUtil.GetStartDate(TimeUtil.StringtoDate(dataReq));
                        //审批提交申请
                        Date date = TimeUtil.GetDate();
                        switch (conditionSort) {
                            //早于
                            case 0:
                                return dateReq.compareTo(date) < 0;
                            //晚于
                            case 1:
                                return dateReq.compareTo(date) > 0;
                            //等于
                            case 2:
                                return dateReq.compareTo(date) == 0;
                            default:
                                return false;
                        }
                    case CONDITION_SUBTYPE_RANGE://日期范围
                        //接收到的 日期范围
                        List<String> dateReqList = JSON.parseArray(dataReq, String.class);
                        Date startDateReq = TimeUtil.GetStartDate(TimeUtil.StringtoDate(dateReqList.get(0)));
                        Date endDateReq = TimeUtil.GetStartDate(TimeUtil.StringtoDate(dateReqList.get(1)));
                        //条件中设置的 日期范围
                        List<String> dateList = JSON.parseArray(condition.getData(), String.class);
                        Date startDate = TimeUtil.GetStartDate(TimeUtil.StringtoDate(dateList.get(0)));
                        Date endDate = TimeUtil.GetStartDate(TimeUtil.StringtoDate(dateList.get(1)));
                        //是否有交集标志
                        boolean flag = true;
                        if (startDateReq.compareTo(endDate) > 0 || endDateReq.compareTo(startDate) < 0) {
                            flag = false;
                        }
                        switch (conditionSort) {
                            //无交集
                            case 0:
                                return !flag;
                            //有交集
                            case 1:
                                return flag;
                            default:
                                return false;
                        }
                    case CONDITION_SUBTYPE_SWITCH://开关
                        switch (conditionSort) {
                            //否
                            case 0:
                                return dataReq.equals("false");
                            //是
                            case 1:
                                return dataReq.equals("true");
                            default:
                                return false;
                        }
                    default:
                        return false;
                }
            }
            return false;
        }).collect(Collectors.toList());

        return collect.size() == conditionList.size();
    }

    /**
     * 传入需通知的节点，向后通知
     *
     * @param nodeDetail    需通知的节点
     * @param userId        用户id
     * @param applicationId 申请表id
     * @param noticeType    通知类型 1：提交申请后通知  2：审批后通知  3:抄送我通知  4:转交或回退通知
     */
    public void notice(AppProcessNodeDetail nodeDetail, String userId, String applicationId, int noticeType) {
        while (true) {
            if (nodeDetail.getType() == APPROVE_NODE) {
                newTips(nodeDetail, userId, applicationId, noticeType);
                break;
            } else if (nodeDetail.getType() == COPY_NODE) {
                nodeDetail.setAllowType(NODE_ALLOW_STATUS_PASS);
                nodeDetail.setAllowTime(new Date());
                appProcessNodeDetailMapper.updateById(nodeDetail);
                newTips(nodeDetail, userId, applicationId, COPY_ME_APPLICATION_NOTICE);
                nodeDetail = getNextNodeDetail(nodeDetail);
            } else if (nodeDetail.getType() == END_NODE) {
                break;
            }
        }
    }

    /**
     * 根据申请表id获取"标题"控件内容
     *
     * @param applicationId 申请表id
     * @return "标题"控件内容
     */
    public String getNoticeMessage(String applicationId) {
        String noticeMessage = "";
        List<AppApplicationData> dataList = appApplicationDataMapper.selectList(new LambdaQueryWrapper<AppApplicationData>()
                .eq(AppApplicationData::getApplicationId, applicationId)
                .eq(AppApplicationData::getType, TEXT_CONTROL_TYPE_NOTICE));
        if (!dataList.isEmpty()) {
            noticeMessage = dataList.get(0).getData();
        }

        return noticeMessage;
    }

    /**
     * 通知当前节点
     *
     * @param nodeDetail    需通知的节点
     * @param userId        用户id
     * @param applicationId 申请表id
     * @param noticeType    通知类型 1：提交申请后通知  2：审批后通知  3:抄送我通知  4:转交或回退通知
     */
    public void newTips(AppProcessNodeDetail nodeDetail, String userId, String applicationId, int noticeType) {
        RangeTypeEnum rangeTypeEnum = null;
        if (nodeDetail.getApproverType() == DYNAMIC_APP_ASSIGNER) {
            rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
        } else if (nodeDetail.getApproverType() == DYNAMIC_APP_ROLE) {
            rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_ROLE;
        } else {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.MESSAGE_NOTICE_FAIL));
        }

        List<String> rangeIdList = new ArrayList<>();
        rangeIdList.add(nodeDetail.getApproverObjectId());

        if (noticeType == SUBMIT_APPLICATION_NOTICE) {
            //获取应用信息
            AppBasicInfo appBasicInfo = appBasicInfoMapper.selectById(appApplicationMapper.selectById(applicationId).getAppId());
            String noticeMessage = getNoticeMessage(applicationId);
            newTipsUtil.addNewTips(TipsTypeEnum.TIPS_TYPE_ENUM_ALLOW,
                    userId,
                    rangeTypeEnum,
                    rangeIdList,
                    COPY_TYPE_ENUM_NONE,
                    null,
                    null,
                    applicationId,
                    null,
                    null,
                    nodeDetail.getId(),
                    null,
                    appBasicInfo.getAppType(),
                    appBasicInfo.getAppName(),
                    noticeMessage);
        } else if (noticeType == ALLOW_APPLICATION_NOTICE) {
            newTipsUtil.allowContinueTips(applicationId,
                    userId,
                    rangeTypeEnum,
                    rangeIdList,
                    nodeDetail.getId());
        } else if (noticeType == TRANS_OR_BACK_APPLICATION_NOTICE) {
            newTipsUtil.allowContinueTips(applicationId,
                    null,
                    rangeTypeEnum,
                    rangeIdList,
                    nodeDetail.getId());
        } else if (noticeType == COPY_ME_APPLICATION_NOTICE) {
            //获取应用信息
            AppBasicInfo appBasicInfo = appBasicInfoMapper.selectById(appApplicationMapper.selectById(applicationId).getAppId());
            String noticeMessage = getNoticeMessage(applicationId);
            newTipsUtil.addNewTips(TipsTypeEnum.TIPS_TYPE_ENUM_MESSAGE,
                    userId,
                    rangeTypeEnum,
                    rangeIdList,
                    rangeTypeEnum == RangeTypeEnum.RANGE_TYPE_ENUM_PERSON ? CopyTypeEnum.COPY_TYPE_ENUM_PERSON : CopyTypeEnum.COPY_TYPE_ENUM_ROLE,
                    rangeIdList,
                    AppTypeEnum.APP_TYPE_ENUM_DYNAMIC_APP,
                    applicationId,
                    null,
                    TipsRecordStatusEnum.TIPS_RECORD_STATUS_ENUM_COPY,
                    nodeDetail.getId(),
                    null,
                    appBasicInfo.getAppType(),
                    appBasicInfo.getAppName(),
                    noticeMessage);
        }
    }

    /**
     * 获取子节点集合
     *
     * @param node 当前节点
     * @return 子节点集合
     */
    public List<AppProcessNodeConfig> getNextNodeList(AppProcessNodeConfig node) {
        return appProcessNodeConfigMapper.selectBatchIds(JSON.parseArray(node.getNextId(), String.class));
    }

    /**
     * 获取父节点集合
     *
     * @param node 当前节点
     * @return 父节点集合
     */
    public List<AppProcessNodeConfig> getPrevNodeList(AppProcessNodeConfig node) {
        return appProcessNodeConfigMapper.selectBatchIds(JSON.parseArray(node.getPrevId(), String.class));
    }

    /**
     * 获取下一个节点
     *
     * @param node 当前节点
     * @return 下一个节点
     */
    public AppProcessNodeConfig getNextNode(AppProcessNodeConfig node) {
        String nextId = JSON.parseArray(node.getNextId(), String.class).get(0);
        return appProcessNodeConfigMapper.selectById(nextId);
    }

    /**
     * 获取上一个节点
     *
     * @param node 当前节点
     * @return 上一个节点
     */
    public AppProcessNodeConfig getPrevNode(AppProcessNodeConfig node) {
        String prevId = JSON.parseArray(node.getPrevId(), String.class).get(0);
        return appProcessNodeConfigMapper.selectById(prevId);
    }

    /**
     * 获取前一个节点详情
     *
     * @param nodeDetail 当前节点详情
     * @return 前一个节点详情
     */
    public AppProcessNodeDetail getPrevNodeDetail(AppProcessNodeDetail nodeDetail) {
        List<AppProcessNodeDetail> nodeDetailList = appProcessNodeDetailMapper.selectList(new LambdaQueryWrapper<AppProcessNodeDetail>()
                .eq(AppProcessNodeDetail::getApplicationId, nodeDetail.getApplicationId())
                .eq(AppProcessNodeDetail::getSort, nodeDetail.getSort() - 1));
        if (nodeDetailList.isEmpty()) {
            return null;
        }
        return nodeDetailList.get(0);
    }

    /**
     * 获取后一个节点详情
     *
     * @param nodeDetail 当前节点详情
     * @return 后一个节点详情
     */
    public AppProcessNodeDetail getNextNodeDetail(AppProcessNodeDetail nodeDetail) {
        List<AppProcessNodeDetail> nodeDetailList = appProcessNodeDetailMapper.selectList(new LambdaQueryWrapper<AppProcessNodeDetail>()
                .eq(AppProcessNodeDetail::getApplicationId, nodeDetail.getApplicationId())
                .eq(AppProcessNodeDetail::getSort, nodeDetail.getSort() + 1));
        if (nodeDetailList.isEmpty()) {
            return null;
        }
        return nodeDetailList.get(0);
    }

    /**
     * 传入当前节点,返回上个状态为通过的审批节点
     *
     * @param nodeDetail 当前节点
     * @return 上个状态为通过的审批节点
     */
    public AppProcessNodeDetail getPrevApprovePassNode(AppProcessNodeDetail nodeDetail) {
        while (true) {
            AppProcessNodeDetail prevNode = getPrevNodeDetail(nodeDetail);
            if (prevNode.getType() == APPLICANT_NODE || prevNode.getType() == APPROVE_NODE) {
                return prevNode;
            } else if (prevNode.getAllowType() != NODE_ALLOW_STATUS_PASS) {
                return null;
            }
        }
    }

    /**
     * 文件下载类接口工具
     *
     * @param future Future数据
     * @return 返回消息
     */
    public ResponseResult exportApplyUtil(Future<ResponseResult> future) {
        ResponseResult responseResult;
        try {
            while (true) {
                if (future.isDone()) {
                    break;
                }
            }
            responseResult = future.get();
        } catch (Exception e) {
            e.printStackTrace();
            responseResult = CommonResult.failed(CommonCodeEnum.FAIL);
        }
        return responseResult;
    }

}
